package cn.cloudtogo.server.mysql.service;

import cn.cloudtogo.common.GendbException;
import cn.cloudtogo.common.types.RequestHeaderObject;
import cn.cloudtogo.server.mysql.SpringJdbcTemplateContext;
import cn.cloudtogo.support.mysql.schema.SchemaApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.stereotype.Component;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.cloudtogo.common.GendbGlobalConstant.SCHEMA_SYSTEM;
import static cn.cloudtogo.common.util.StringHelper.pretty;

/**
 * @author yaolianhua789@gmail.com
 **/
@Component
@Slf4j
public class Schemas implements SchemaApi {

    public static final List<String> SYSTEM_SCHEMAS = List.of("information_schema", "performance_schema", "mysql", "sys", SCHEMA_SYSTEM);
    private final SpringJdbcTemplateContext context;

    public Schemas(SpringJdbcTemplateContext springJdbcTemplateContext) {
        this.context = springJdbcTemplateContext;
    }

    @Override
    public void create(String name, boolean useIfNotExist, RequestHeaderObject requestHeaderObject) {
        JdbcTemplate jdbc = context.getJdbcTemplate(requestHeaderObject);
        if (useIfNotExist) {
            String sql = String.format("create schema if not exists %s", name);
            log.debug(pretty(requestHeaderObject, "Create schema", null, sql));
            jdbc.execute(sql);
            log.info("create schema '{}' success ", name);
            return;
        }
        String sql = String.format("create schema %s", name);
        log.debug(pretty(requestHeaderObject, "Create schema", null, sql));
        jdbc.execute(sql);
        log.info("create schema '{}' success", name);
    }

    @Override
    public void delete(String name, RequestHeaderObject requestHeaderObject) {
        List<String> schemas = list(requestHeaderObject);
        if (!schemas.contains(name)) {
            throw new GendbException(String.format("schema '%s' does not exist", name));
        }

        JdbcTemplate jdbc = context.getJdbcTemplate(requestHeaderObject);
        String sql = String.format("drop schema if exists %s", name);
        log.debug(pretty(requestHeaderObject, "Drop schema", null, sql));
        jdbc.execute(sql);
        log.info("delete schema '{}' success", name);
    }

    @Override
    public List<String> list(RequestHeaderObject requestHeaderObject) {
        JdbcTemplate jdbc = context.getJdbcTemplate(requestHeaderObject);
        List<String> schemas = new LinkedList<>();
        try {
            ResultSet resultSet = JdbcUtils.extractDatabaseMetaData(Objects.requireNonNull(jdbc.getDataSource()), DatabaseMetaData::getCatalogs);
            while (resultSet.next()) {
                schemas.add(resultSet.getString(1));
            }

        } catch (MetaDataAccessException | SQLException e) {
            log.error("list schemas error '{}'", e.getMessage(), e);
            throw new GendbException(String.format("list schemas error '%s'", e.getMessage()));
        }
        log.debug(pretty(requestHeaderObject, "List schemas", null, null));
        List<String> filteredSchemas = schemas.stream()
                .filter(e -> !SYSTEM_SCHEMAS.contains(e))
                .collect(Collectors.toList());
        return filteredSchemas;
    }
}
